/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package View;

import controller.Traffic;
import Model.Car;
import Model.Const;
import Model.IntersectionInfo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.event.ActionListener;
import java.util.zip.DataFormatException;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

/**
 *
 * @author Administrator
 */
public class Display extends JFrame {

    private IntersectionInfo oIntersectionInfo;
    private Traffic oTraffic;
    private JTextField textLanesHoriz;
    private JTextField textLanesVert;
    private JTextField textProbabilityHoriz;
    private JTextField textProbabilityVert;
    private JButton buttonSetInfo;
    private JButton buttonStartSimulation;
    private JButton buttonEndSimulation;

    public Display(IntersectionInfo oIntersectionInfo, Traffic oTraffic){

        this.oIntersectionInfo = oIntersectionInfo;
        this.oTraffic = oTraffic;

        JLabel labelLanesHoriz = new JLabel(Const.MENU_MAIN_GUI_HORIZ_LANES_NUM);
        JLabel labelLanesVert = new JLabel(Const.MENU_MAIN_GUI_VERT_LANES_NUM);
        JLabel labelProbabilityHoriz = new JLabel(Const.MENU_MAIN_GUI_PROBABILITY_ENTER_HORIZ);
        JLabel labelProbabilityVert = new JLabel(Const.MENU_MAIN_GUI_PROBABILITY_ENTER_VERT);

        labelLanesHoriz.setHorizontalAlignment(JLabel.RIGHT);
        labelLanesVert.setHorizontalAlignment(JLabel.RIGHT);
        labelProbabilityHoriz.setHorizontalAlignment(JLabel.RIGHT);
        labelProbabilityVert.setHorizontalAlignment(JLabel.RIGHT);

        textLanesHoriz = new JTextField(4);
        textLanesVert = new JTextField(4);
        textProbabilityHoriz = new JTextField(4);
        textProbabilityVert = new JTextField(4);
        buttonSetInfo = new JButton("Set");
        buttonStartSimulation = new JButton("Start");
        buttonEndSimulation = new JButton("End");

        textLanesHoriz.setHorizontalAlignment(JTextField.CENTER);
        textLanesVert.setHorizontalAlignment(JTextField.CENTER);
        textProbabilityHoriz.setHorizontalAlignment(JTextField.CENTER);
        textProbabilityVert.setHorizontalAlignment(JTextField.CENTER);

        // set default values
        textLanesHoriz.setText("2");
        textLanesVert.setText("2");
        textProbabilityHoriz.setText("0.5");
        textProbabilityVert.setText("0.5");

        JPanel panelMainDisplay = new JPanel();
        BorderLayout borderLayoutMain = new BorderLayout();
        borderLayoutMain.setHgap(6);
        borderLayoutMain.setVgap(6);
        panelMainDisplay.setLayout(borderLayoutMain);
        
        JPanel panelButtons = new JPanel();
//        GridLayout gridLayoutButtons = new GridLayout(6,2);
//        gridLayoutButtons.setHgap(6);
//        gridLayoutButtons.setVgap(6);

        GridBagLayout oGridbag = new GridBagLayout();
        panelButtons.setLayout(oGridbag);

        JLabel labelSpace1 = new JLabel(" ");
        JLabel labelSpace2 = new JLabel(" ");
        JLabel labelSpace3 = new JLabel(" ");
        JLabel labelSpace4 = new JLabel(" ");
        JLabel labelSpace5 = new JLabel(" ");
        JLabel labelSpace6 = new JLabel(" ");

        addGridComp(panelButtons, oGridbag, labelSpace1, 0, 0, 2, 1);
        addGridComp(panelButtons, oGridbag, labelSpace2, 2, 0, 2, 1);
        addGridComp(panelButtons, oGridbag, labelSpace3, 4, 0, 2, 1);
        addGridComp(panelButtons, oGridbag, labelSpace4, 6, 0, 2, 1);
        addGridComp(panelButtons, oGridbag, labelSpace5, 8, 0, 2, 1);
        addGridComp(panelButtons, oGridbag, labelSpace6, 10, 0, 2, 1);

        addGridComp(panelButtons, oGridbag, labelLanesHoriz, 1, 1, 6, 1);
        addGridComp(panelButtons, oGridbag, labelLanesVert, 1, 2, 6, 1);
        addGridComp(panelButtons, oGridbag, labelProbabilityHoriz, 1, 3, 6, 1);
        addGridComp(panelButtons, oGridbag, labelProbabilityVert, 1, 4, 6, 1);
        addGridComp(panelButtons, oGridbag, textLanesHoriz, 6, 1, 2, 1);
        addGridComp(panelButtons, oGridbag, textLanesVert, 6, 2, 2, 1);
        addGridComp(panelButtons, oGridbag, textProbabilityHoriz, 6, 3, 2, 1);
        addGridComp(panelButtons, oGridbag, textProbabilityVert, 6, 4, 2, 1);

        addGridComp(panelButtons, oGridbag, buttonSetInfo, 6, 5, 3, 1);
        addGridComp(panelButtons, oGridbag, buttonStartSimulation, 2, 6, 3, 1);
        addGridComp(panelButtons, oGridbag, buttonEndSimulation, 4, 6, 3, 1);


//        panelButtons.setLayout(gridLayoutButtons);
//
//        panelButtons.add(labelLanesHoriz);
//        panelButtons.add(textLanesHoriz);
//        panelButtons.add(labelLanesVert);
//        panelButtons.add(textLanesVert);
//        panelButtons.add(labelProbabilityHoriz);
//        panelButtons.add(textProbabilityHoriz);
//        panelButtons.add(labelProbabilityVert);
//        panelButtons.add(textProbabilityVert);
//        panelButtons.add(new JLabel());
//        panelButtons.add(buttonSetInfo);
//        panelButtons.add(buttonStartSimulation);
//        panelButtons.add(buttonEndSimulation);

        panelMainDisplay.add(panelButtons, BorderLayout.NORTH);
        panelMainDisplay.add(new GPanel(), BorderLayout.CENTER);
        this.setContentPane(panelMainDisplay);
        this.pack();

        this.setTitle("GUI Traffic Sumilator Ver.1.0");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(800, 700);
        this.setLocationByPlatform(true);
    }

    class GPanel extends JPanel {

        GPanel(){

        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            int nPanelSize = 0;
            int nMarginLeft = 0;
            int nMarginTop = 0;
            int panel_width = this.getWidth();
            int panel_hight = this.getHeight();
            int lane_width = Const.LANE_WIDTH;
            int x1;
            int y1;
            int x2;
            int y2;
            int width;
            int hight;
            Image oImageCar;

            g.setColor(Color.BLACK);

            int nLaneHoriz = oIntersectionInfo.getLaneHoriz();
            int nLaneVert = oIntersectionInfo.getLaneVert();

            if (panel_width > panel_hight){
                nPanelSize = panel_hight;
                nMarginLeft = (panel_width-panel_hight)/2;
                nMarginTop = 0;
            }
            else{
                nPanelSize = panel_width;
                nMarginLeft = 0;
                nMarginTop = (panel_hight-panel_width)/2;
            }

            int nMaxLane = Const.MAX_VERT_LANES;
            int nStreetLength = (nPanelSize - nMaxLane*Const.LANE_WIDTH)/2;

            // adjust left margin
            nMarginLeft += (nMaxLane - nLaneVert)*Const.LANE_WIDTH/2;

            // adjust top margin
            nMarginTop += (nMaxLane - nLaneHoriz)*Const.LANE_WIDTH/2;

            // intersection horizontal size
            int nInterHorizSize = nLaneVert*Const.LANE_WIDTH;

            // intersection vertical size
            int nInterVertSize = nLaneHoriz*Const.LANE_WIDTH;

            // draw horizontal lane
            for (int nLane=0; nLane<nLaneHoriz+1; nLane++){

                x1 = nMarginLeft;
                y1 = nMarginTop + nStreetLength + nLane*Const.LANE_WIDTH;
                x2 = x1 + nStreetLength;
                y2 = y1;
                g.drawLine(x1, y1, x2, y2);

                // draw traffic light of vertical lane
                if (oTraffic.getfTraficLightVert()==Const.LIGHT_RED & nLane==0){
                    g.setColor(Color.RED);
                    x1 = nMarginLeft + nStreetLength;
                    y1 = nMarginTop + nStreetLength + nLane*Const.LANE_WIDTH;
                    x2 = x1 + nInterHorizSize;
                    y2 = y1;
                    width = nInterHorizSize;
                    hight = 4;                    
//                  g.drawLine(x1, y1, x2, y2);                    
                    g.fillRect(x1, y1, width, hight);
                    g.setColor(Color.BLACK);
                }

                x1 = nMarginLeft + nStreetLength + nInterHorizSize;
                y1 = nMarginTop + nStreetLength + nLane*Const.LANE_WIDTH;
                x2 = x1 + nStreetLength;
                y2 = y1;
                g.drawLine(x1, y1, x2, y2);
            }

            // draw vetical lane
            for (int nLane=0; nLane<nLaneVert+1; nLane++){

                x1 = nMarginLeft + nStreetLength + nLane*Const.LANE_WIDTH;
                y1 = nMarginTop;
                x2 = x1;
                y2 = y1 + nStreetLength;
                g.drawLine(x1, y1, x2, y2);

                // draw traffic light of vertical lane
                if (oTraffic.getfTraficLightHoriz()==Const.LIGHT_RED & nLane==0){
                    g.setColor(Color.RED);
                    x1 = nMarginLeft + nStreetLength + nLane*Const.LANE_WIDTH;
                    y1 = nMarginTop + nStreetLength;
                    x2 = x1;
                    y2 = y1 + nInterVertSize;
                    width = 4;
                    hight = nInterVertSize;
//                  g.drawLine(x1, y1, x2, y2);
                    g.fillRect(x1, y1, width, hight);
                    g.setColor(Color.BLACK);
                }

                x1 = nMarginLeft + nStreetLength + nLane*Const.LANE_WIDTH;
                y1 = nMarginTop + nStreetLength + nInterVertSize;
                x2 = x1;
                y2 = y1 + nStreetLength;
                g.drawLine(x1, y1, x2, y2);
            }

            int nRoadLenghtHoriz = oIntersectionInfo.getRoadLenghtHoriz();
            int nRoadLenghtVert = oIntersectionInfo.getRoadLenghtVert();

            // drow car on the horzontal street
            for (int nLane=0; nLane<nLaneHoriz; nLane++){

                for (int nPosCar=0; nPosCar<nRoadLenghtHoriz; nPosCar++){
                    Car oCar = oTraffic.getCarOnStreet(nLane, Const.STREET_POSITION_WEST, nPosCar);
                    if (oCar != null){

                        x1 = nMarginLeft + nPosCar*(nStreetLength/nRoadLenghtHoriz) + Const.CAR_MARGIN;
                        y1 = nMarginTop + nStreetLength + nLane*Const.LANE_WIDTH + Const.CAR_MARGIN;
                        width = nStreetLength/nRoadLenghtHoriz - Const.CAR_MARGIN*2;
                        hight = Const.LANE_WIDTH - Const.CAR_MARGIN*2;
//                        g.fillRect(x1, y1, width, hight);
                        oImageCar = oCar.getImageCarHoriz();
                        g.drawImage(oImageCar, x1, y1, width, hight, this);
                    }
                }

                for (int nPosCar=0; nPosCar<nRoadLenghtHoriz; nPosCar++){
                    Car oCar = oTraffic.getCarOnStreet(nLane, Const.STREET_POSITION_EAST, nPosCar);
                    if (oCar != null){

                        x1 = nMarginLeft + nStreetLength + nInterHorizSize + nPosCar*(nStreetLength/nRoadLenghtHoriz) + Const.CAR_MARGIN;
                        y1 = nMarginTop + nStreetLength + nLane*Const.LANE_WIDTH + Const.CAR_MARGIN;
                        width = nStreetLength/nRoadLenghtHoriz - Const.CAR_MARGIN*2;
                        hight = Const.LANE_WIDTH - Const.CAR_MARGIN*2;
//                        g.fillRect(x1, y1, width, hight);
                        oImageCar = oCar.getImageCarHoriz();
                        g.drawImage(oImageCar, x1, y1, width, hight, this);
                    }
                }
            }

            // drow car on the vertical street
            for (int nLane=0; nLane<nLaneVert; nLane++){

                for (int nPosCar=0; nPosCar<nRoadLenghtVert; nPosCar++){
                    Car oCar = oTraffic.getCarOnStreet(nLane, Const.STREET_POSITION_NORTH, nPosCar);
                    if (oCar != null){

                        x1 = nMarginLeft + nStreetLength + nLane*Const.LANE_WIDTH + Const.CAR_MARGIN;
                        y1 = nMarginTop + nPosCar*(nStreetLength/nRoadLenghtVert) + Const.CAR_MARGIN;
                        width = Const.LANE_WIDTH - Const.CAR_MARGIN*2;
                        hight = nStreetLength/nRoadLenghtVert - Const.CAR_MARGIN*2;
//                        g.fillRect(x1, y1, width, hight);
                        oImageCar = oCar.getImageCarVert();
                        g.drawImage(oImageCar, x1, y1, width, hight, this);
                    }
                }

                for (int nPosCar=0; nPosCar<nRoadLenghtVert; nPosCar++){
                    Car oCar = oTraffic.getCarOnStreet(nLane, Const.STREET_POSITION_SOUTH, nPosCar);
                    if (oCar != null){

                        x1 = nMarginLeft + nStreetLength + nLane*Const.LANE_WIDTH + Const.CAR_MARGIN;
                        y1 = nMarginTop + nStreetLength + nInterVertSize + nPosCar*(nStreetLength/nRoadLenghtVert) + Const.CAR_MARGIN;
                        width = Const.LANE_WIDTH - Const.CAR_MARGIN*2;
                        hight = nStreetLength/nRoadLenghtVert - Const.CAR_MARGIN*2;
//                        g.fillRect(x1, y1, width, hight);
                        oImageCar = oCar.getImageCarVert();
                        g.drawImage(oImageCar, x1, y1, width, hight, this);
                    }
                }

            }
        }
    }

    private void addGridComp(JPanel panelButtons, GridBagLayout oGridBag, JComponent oJComponent, int x, int y, int w, int h) {
        GridBagConstraints oConstraints = new GridBagConstraints();
        oConstraints.fill = GridBagConstraints.BOTH;
        oConstraints.weightx = 100.0;
        oConstraints.weighty = 100.0;
        oConstraints.gridx = x;
        oConstraints.gridy = y;
        oConstraints.gridwidth = w;
        oConstraints.gridheight = h;
        oGridBag.setConstraints(oJComponent, oConstraints);
        panelButtons.add(oJComponent);
    }

    public void addListenerSetInfoButton(ActionListener oListnerClass) {
        buttonSetInfo.addActionListener(oListnerClass);
    }

    public void addListenerStartButton(ActionListener oListnerClass) {
        buttonStartSimulation.addActionListener(oListnerClass);
    }

    public void addListenerEndButton(ActionListener oListnerClass) {
        buttonEndSimulation.addActionListener(oListnerClass);
    }

    public void setTraffic(Traffic oTraffic) {
        this.oTraffic = oTraffic;
    }

    public void setIntersectionInfo(IntersectionInfo oIntersectionInfo) {
        this.oIntersectionInfo = oIntersectionInfo;
    }

    public int getLanesHoriz() throws DataFormatException{

        try{
            String stLanesHoriz = textLanesHoriz.getText();
            int nLanesHoriz = Integer.parseInt(stLanesHoriz);

            if(nLanesHoriz < Const.MIN_HORIZ_LANES || Const.MAX_HORIZ_LANES < nLanesHoriz) {
                String stHeader = "\n\n" + Const.MENU_MAIN_GUI_HORIZ_LANES_NUM + '\n';
                throw new DataFormatException(stHeader + String.format(Const.ERR_GUI_MSG_INPUT_RANGE, Const.MIN_HORIZ_LANES, Const.MAX_HORIZ_LANES));
            }

            return nLanesHoriz;
        }
        catch (DataFormatException e){

            throw e;
        }
        catch (Exception e){

            String stHeader = "\n\n" + Const.MENU_MAIN_GUI_HORIZ_LANES_NUM + '\n';
            throw new DataFormatException(stHeader + Const.ERR_GUI_MSG_INPUT_NOT_NUMBER);
        }
}

    public int getLanesVert() throws DataFormatException{

        try{
            String stLanesVert = textLanesVert.getText();
            int nLanesVert = Integer.parseInt(stLanesVert);

            if(nLanesVert < Const.MIN_VERT_LANES || Const.MAX_VERT_LANES < nLanesVert) {
                String stHeader = "\n\n" + Const.MENU_MAIN_GUI_VERT_LANES_NUM + '\n';
                throw new DataFormatException(stHeader + String.format(Const.ERR_GUI_MSG_INPUT_RANGE, Const.MIN_VERT_LANES, Const.MAX_VERT_LANES));
            }

            return nLanesVert;
        }
        catch (DataFormatException e){

            throw e;
        }
        catch (Exception e){

            String stHeader = "\n\n" + Const.MENU_MAIN_GUI_VERT_LANES_NUM + '\n';
            throw new DataFormatException(stHeader + Const.ERR_GUI_MSG_INPUT_NOT_NUMBER);
        }
    }

    public float getProbabilityHoriz() throws DataFormatException{

        try{
            float fProbabilityHoriz;

            String stProbabilityHoriz = textProbabilityHoriz.getText();
            fProbabilityHoriz = Float.parseFloat(stProbabilityHoriz);

            if(fProbabilityHoriz < Const.MIN_PROBABILITY_HORIZ || Const.MAX_PROBABILITY_HORIZ < fProbabilityHoriz) {
                String stHeader = "\n\n" + Const.MENU_MAIN_GUI_PROBABILITY_ENTER_HORIZ + '\n';
                throw new DataFormatException(stHeader + String.format(Const.ERR_GUI_MSG_INPUT_RANGE, Const.MIN_PROBABILITY_HORIZ, Const.MAX_PROBABILITY_HORIZ));
            }

            return fProbabilityHoriz;
        }
        catch (DataFormatException e){

            throw e;
        }
        catch (Exception e){

            String stHeader = "\n\n" + Const.MENU_MAIN_GUI_PROBABILITY_ENTER_HORIZ + '\n';
            throw new DataFormatException(stHeader + Const.ERR_GUI_MSG_INPUT_NOT_NUMBER);
        }
    }

    public float getProbabilityVert() throws DataFormatException{

        try{
            String stProbabilityVert = textProbabilityVert.getText();
            float fProbabilityVert = Float.parseFloat(stProbabilityVert);

            if(fProbabilityVert < Const.MIN_PROBABILITY_VERT || Const.MAX_PROBABILITY_VERT < fProbabilityVert) {
                String stHeader = "\n\n" + Const.MENU_MAIN_GUI_PROBABILITY_ENTER_VERT + '\n';
                throw new DataFormatException(stHeader + String.format(Const.ERR_GUI_MSG_INPUT_RANGE, Const.MIN_PROBABILITY_HORIZ, Const.MAX_PROBABILITY_HORIZ));
            }

            return fProbabilityVert;
        }
        catch (DataFormatException e){

            throw e;
        }
        catch (Exception e){

            String stHeader = "\n\n" + Const.MENU_MAIN_GUI_PROBABILITY_ENTER_VERT + '\n';
            throw new DataFormatException(stHeader + Const.ERR_GUI_MSG_INPUT_NOT_NUMBER);
        }
    }
}
